<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2020/6/8
 * Time: 15:32
 */
require_once __DIR__ . '/api/common/RichesmeAppRedis.php';

class FilterRequest
{
    protected $redis_client = null;
    private static $instance = null;
    private $KEY_IP = 'safe.control.visit.ip';
    private $KEY_SCORE_SET_IP_NEED_CONTROL = 'safe.need_control.ip';//需要管控的ip列表 访问次数
    private $KEY_HASH_IP_NEED_CONTROL = 'safe.need_control.list.ip:';//ip的详细信息
    private $KEY_SET_BLACK_IP_CONTROL = 'safe.need_control.black_list.ip';//黑名单
    private $KEY_SET_WHITE_IP_CONTROL = 'safe.need_control.white_list.ip';//白名单

    private function __construct()
    {
//        if ($this->redis_client == null) {
//            $this->redis_client = RichesmeAppRedis::getInstance();
//        }
    }

    public static function getInstance()
    {
        if (self::$instance == null) {
            self::$instance = new FilterRequest();
        }
        return self::$instance;
    }

    private function errResponse($code)
    {
        switch ($code) {
            case 4001:
                echo json_encode(['code' => $code, 'msg' => '在黑名单内']);

                break;
            case 4002:
                echo json_encode(['code' => $code, 'msg' => '请求过于频繁']);
                break;
        }
        exit();
    }

    /**
     * 限制ip请求次数 规定时间内请求次数达到一定次数
     * @param int $limit 10次
     * @param int $expire_time 60秒
     */
    public function filterIp($ip, $limit = 30, $expire_time = 60)
    {
        $key = $ip;
        //判断ip是否在白名单或者黑名单中
        if (in_array($ip, $this->getBlackList())) {
            $this->errResponse(4001);
        }
        if (!in_array($ip, $this->getWhiteList())) {

//限制次数为5
//        $limit = 10;
//        $expire_time = 60;
            $check = RichesmeAppRedis::getInstance()->exists($key);
            if ($check) {
                RichesmeAppRedis::getInstance()->incr($key);
                $count = RichesmeAppRedis::getInstance()->get($key);
                if ($count > $limit) {
                    $this->errResponse(4002);
                    exit();
                }
            } else {
                RichesmeAppRedis::getInstance()->set($key,1);
                //限制时间为60秒
                RichesmeAppRedis::getInstance()->expire($key, $expire_time);
            }
        }
    }

    /**
     * 获得今天剩余秒数
     * @return false|int
     */
    public function getTodayResidueTime()
    {
        $now = time();
        $end=strtotime(date('Y-m-d ') . '23:59:59');
        $res=$end - $now;
        if($res<1){
            $res = 1;
        }
        return (int)$res;
    }

    /**
     * 记录ip访问次数
     * @param $ip
     */
    public function recordIp($ip)
    {
        if (in_array($ip, $this->getBlackList())) {
            $this->errResponse(4001);
        }

        $key = $this->KEY_SCORE_SET_IP_NEED_CONTROL;
        if (!RichesmeAppRedis::getInstance()->exists($key)) {
            RichesmeAppRedis::getInstance()->zadd($key, [$ip => 1]);
            RichesmeAppRedis::getInstance()->expire($key, $this->getTodayResidueTime());//24小时
        } else {
            RichesmeAppRedis::getInstance()->zincrby($key, 1, $ip);
        }
        //记录每个ip的一些信息
        //第一次访问时间 最后访问时间
        $key2 = $this->KEY_HASH_IP_NEED_CONTROL . $ip;
        if (!RichesmeAppRedis::getInstance()->exists($key2)) {
            RichesmeAppRedis::getInstance()->hset($key2, 'first_visit_time', time());
            RichesmeAppRedis::getInstance()->hset($key2, 'last_visit_time', time());
            RichesmeAppRedis::getInstance()->expire($key2, $this->getTodayResidueTime());//24小时
        } else {
            RichesmeAppRedis::getInstance()->hset($key2, 'last_visit_time', time());
        }

    }

    /**
     * 获得ip的剩余时间 秒
     * @param $ip
     * @return int
     */
    public function getIpTTl($ip)
    {
        $key2 = $this->KEY_HASH_IP_NEED_CONTROL . $ip;
        return RichesmeAppRedis::getInstance()->ttl($key2)??0;
    }

    /**
     * 添加黑名单
     * @param $ip
     */
    public function addBlackList($ip)
    {
        $key = $this->KEY_SET_BLACK_IP_CONTROL;
        RichesmeAppRedis::getInstance()->sadd($key, [$ip]);
        if(in_array($ip,$this->getWhiteList())){
            $this->removeIpFromWhiteList($ip);
        }
    }

    /**
     * 把ip从黑名单中删除
     * @param $ip
     */
    public function removeIpFromBlackList($ip)
    {
        $key = $this->KEY_SET_BLACK_IP_CONTROL;
        RichesmeAppRedis::getInstance()->srem($key, $ip);
    }

    /**
     * 添加白名单
     * @param $ip
     */
    public function addWhiteList($ip)
    {
        $key = $this->KEY_SET_WHITE_IP_CONTROL;
        RichesmeAppRedis::getInstance()->sadd($key, [$ip]);
        if(in_array($ip,$this->getBlackList())){
            $this->removeIpFromBlackList($ip);
        }
    }

    /**
     * 把ip从白名单中删除
     * @param $ip
     */
    public function removeIpFromWhiteList($ip)
    {
        $key = $this->KEY_SET_WHITE_IP_CONTROL;
        RichesmeAppRedis::getInstance()->srem($key, $ip);
    }

    /**
     * 黑名单列表
     * @return array
     */
    public function getBlackList()
    {
        $res = RichesmeAppRedis::getInstance()->smembers($this->KEY_SET_BLACK_IP_CONTROL);
        return $res ?? [];
    }

    /**
     * 白名单列表
     * @return array
     */
    public function getWhiteList()
    {
        $res = RichesmeAppRedis::getInstance()->smembers($this->KEY_SET_WHITE_IP_CONTROL);
        return $res ?? [];
    }

    /**
     * 获得访问的ip列表
     * @param int $start
     * @param int $stop
     * @return array
     */
    public function getRecordIp($start = 0, $stop = 10)
    {
        $res = RichesmeAppRedis::getInstance()->zrange($this->KEY_SCORE_SET_IP_NEED_CONTROL, $start, $stop, 'WITHSCORES');
        $data = array();

        foreach ($res as $ind => $re) {
            $ip = $ind;
            $key2 = $this->KEY_HASH_IP_NEED_CONTROL . $ip;
            $tmp = array();
            $tmp['ip'] = $ip;
            $tmp['first_visit_time'] = RichesmeAppRedis::getInstance()->hget($key2, 'first_visit_time');
            $tmp['last_visit_time'] = RichesmeAppRedis::getInstance()->hget($key2, 'last_visit_time');
            $tmp['socres'] = $re;//访问次数
            $data[] = $tmp;
//            echo "ip:{$ind}-----{$re}".PHP_EOL;
        }
        return $data;
    }

    /**
     * 删除ip
     * @param $ip
     */
    public function delIp($ip)
    {
        $key2 = $this->KEY_HASH_IP_NEED_CONTROL . $ip;
        RichesmeAppRedis::getInstance()->del([$key2]);
        $key = $this->KEY_SCORE_SET_IP_NEED_CONTROL;
        RichesmeAppRedis::getInstance()->zrem($key, $ip);
    }

    /**
     * 获取ip的信息
     * @param $ip
     * @return mixed
     */
    public function getIpInfo($ip)
    {
        $key2 = $this->KEY_HASH_IP_NEED_CONTROL . $ip;
        $tmp['ip'] = $ip;
        $tmp['first_visit_time'] = RichesmeAppRedis::getInstance()->hget($key2, 'first_visit_time');
        $tmp['last_visit_time'] = RichesmeAppRedis::getInstance()->hget($key2, 'last_visit_time');
        $tmp['socres'] = RichesmeAppRedis::getInstance()->zscore($this->KEY_SCORE_SET_IP_NEED_CONTROL, $ip);//访问次数
        return $tmp;
    }

    /**
     * 返回总访客的数量
     * @return string
     */
    public function getRecordIpCount()
    {
        return RichesmeAppRedis::getInstance()->zcount($this->KEY_SCORE_SET_IP_NEED_CONTROL, 0, 9999999999);
    }
}